package com.rgs.gateway.admin.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rgs.gateway.admin.entity.dto.GatewayRouteQueryParam;
import com.rgs.gateway.admin.entity.po.GatewayRoutePO;
import com.rgs.gateway.admin.entity.vo.GatewayRouteRespVO;
import com.rgs.gateway.admin.mapper.GatewayRouteMapper;
import com.rgs.gateway.admin.service.IGatewayRouteService;
import com.rgs.gateway.common.enums.YesOrNoEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.net.URI;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author meix
 */
@Service
@Slf4j
public class GatewayRouteServiceImpl extends ServiceImpl<GatewayRouteMapper, GatewayRoutePO> implements IGatewayRouteService {

    private static final String GATEWAY_ROUTES = "api_gateway_routes::";

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean add(GatewayRoutePO gatewayRoute) {
        boolean isSuccess = this.save(gatewayRoute);
        // 转化为gateway需要的类型，缓存到redis, 并事件通知各网关应用
        RouteDefinition routeDefinition = gatewayRouteToRouteDefinition(gatewayRoute);
        redisTemplate.opsForValue().set(GATEWAY_ROUTES + gatewayRoute.getRouteId(), routeDefinition);
        return isSuccess;
    }

    @Override
    public boolean delete(String id) {
        GatewayRoutePO gatewayRoute = this.getById(id);
        // 删除redis缓存, 并事件通知各网关应用
        redisTemplate.opsForValue().decrement(GATEWAY_ROUTES + gatewayRoute.getRouteId());
        return this.removeById(id);
    }

    @Override
    public boolean update(GatewayRoutePO gatewayRoute) {
        boolean isSuccess = this.updateById(gatewayRoute);
        // 转化为gateway需要的类型，缓存到redis, 并事件通知各网关应用
        RouteDefinition routeDefinition = gatewayRouteToRouteDefinition(gatewayRoute);
        redisTemplate.opsForValue().set(GATEWAY_ROUTES + gatewayRoute.getRouteId(), routeDefinition);
        return isSuccess;
    }

    @Override
    public GatewayRoutePO get(String id) {
        return this.getById(id);
    }

    @Override
    public List<GatewayRouteRespVO> query(GatewayRouteQueryParam gatewayRouteQueryParam) {
        QueryWrapper<GatewayRoutePO> queryWrapper = new QueryWrapper<>();
        queryWrapper.ge(null != gatewayRouteQueryParam.getCreatedTimeStart(), "created_time", gatewayRouteQueryParam.getCreatedTimeStart())
                .le(null != gatewayRouteQueryParam.getCreatedTimeEnd(), "created_time", gatewayRouteQueryParam.getCreatedTimeEnd());
        queryWrapper.eq(StringUtils.isNotBlank(gatewayRouteQueryParam.getUri()), "uri", gatewayRouteQueryParam.getUri());
        return this.list(queryWrapper).stream().map(q -> BeanUtil.copyProperties(q, GatewayRouteRespVO.class)).collect(Collectors.toList());
    }

    @Override
    @PostConstruct
    public boolean overload() {
        QueryWrapper<GatewayRoutePO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("isDelete", YesOrNoEnum.NO.getCodeValue());

        //删除全部的key
        Set<String> gatewayKeys = redisTemplate.keys(GATEWAY_ROUTES + "*");
        redisTemplate.delete(gatewayKeys);
        log.info("全局初使化网关路由旧数据删除成功!");

        List<GatewayRoutePO> gatewayRoutes = this.list(queryWrapper);
        gatewayRoutes.forEach(gatewayRoute -> redisTemplate.opsForValue().set(GATEWAY_ROUTES + gatewayRoute.getRouteId(), gatewayRouteToRouteDefinition(gatewayRoute)));
        log.info("全局初使化网关路由成功!");
        return true;
    }


    /**
     * 将数据库中json对象转换为网关需要的RouteDefinition对象
     *
     * @param gatewayRoute
     * @return RouteDefinition
     */
    private RouteDefinition gatewayRouteToRouteDefinition(GatewayRoutePO gatewayRoute) {
        RouteDefinition routeDefinition = new RouteDefinition();
        routeDefinition.setId(gatewayRoute.getRouteId());
        routeDefinition.setOrder(gatewayRoute.getOrders());
        routeDefinition.setUri(URI.create(gatewayRoute.getUrl()));
        // 使用 Hutool 进行转换
        JSONArray jsonArray = JSONUtil.parseArray(gatewayRoute.getFilters());
        routeDefinition.setFilters(jsonArray.toList(FilterDefinition.class));

        JSONArray jsonArray2 = JSONUtil.parseArray(gatewayRoute.getPredicates());
        routeDefinition.setPredicates(jsonArray2.toList(PredicateDefinition.class));
        return routeDefinition;
    }

}
